﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.DataViz.NetworkDiagram.NetworkData.Citations
{
    /// <summary>
    /// 
    /// </summary>
    public class CitationDistanceCalculator:ILinkDistanceCalculator
    {
        #region fields for args
        private string _FromIDField = string.Empty;
        private string _FromNameField = string.Empty;
        private string _ToIDsField = string.Empty;
        private string _ToNamesField = string.Empty;
        private string _FreqField = string.Empty;
        #endregion

        #region Implementation of ILinkDistanceCalculator

        /// <summary>
        /// 
        /// </summary>
        public Dictionary<string, SimpleDataType> RequiredArguments
        {
            get
            {
                Dictionary<string,SimpleDataType> requiredArgs=new Dictionary<string, SimpleDataType>();
                requiredArgs.Add("CitingID",SimpleDataType.IntNumberType);
                requiredArgs.Add("CitedIDs", SimpleDataType.IntListType);
                requiredArgs.Add("CitingName", SimpleDataType.TextType);
                requiredArgs.Add("CitedNames", SimpleDataType.StringListType);
                requiredArgs.Add("CitingFrequency", SimpleDataType.IntNumberType);
                return requiredArgs;
            }
        }

        /// <summary>
        /// setup field -> arg mappings
        /// </summary>
        /// <param name="mappings"></param>
        public void InitFieldMappings(Dictionary<string,string> mappings)
        {
            if (mappings != null && mappings.Count > 0)
            {
                foreach (string key in mappings.Keys)
                {
                    if (mappings[key] == "CitingID")
                        this._FromIDField = key;
                    else if (mappings[key] == "CitedIDs")
                        this._ToIDsField = key;
                    else if (mappings[key] == "CitingName")
                        this._FromNameField = key;
                    else if (mappings[key] == "CitedNames")
                        this._ToNamesField = key;
                    else if (mappings[key] == "CitingFrequency")
                        this._FreqField = key;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dr1"></param>
        /// <param name="dr2"></param>
        /// <returns></returns>
        public double? CalculateLinkDistance(DataRow dr1, DataRow dr2)
        {
            if (!string.IsNullOrEmpty(this._FromIDField) && !string.IsNullOrEmpty(this._ToIDsField))
            {
                if (dr1[this._ToIDsField] != null && dr2[this._FromIDField] != null &&
                    ((List<int>)dr1[this._ToIDsField]).Contains(((int)dr2[this._FromIDField])))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && dr1[this._FreqField] != null)
                    {
                        int freq = (int)dr1[this._FreqField];
                        if (freq > 0)
                            return 1.0/Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
                else if (dr2[this._ToIDsField] != null && dr1[this._FromIDField] != null &&
                    ((List<int>)dr2[this._ToIDsField]).Contains(((int)dr1[this._FromIDField])))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && dr2[this._FreqField] != null)
                    {
                        int freq = (int)dr2[this._FreqField];
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
            }
            if (!string.IsNullOrEmpty(this._FromNameField) && !string.IsNullOrEmpty(this._ToNamesField))
            {
                if (dr1[this._ToNamesField] != null && dr2[this._FromNameField] != null &&
                    ((List<string>)dr1[this._ToNamesField]).Contains(((string)dr2[this._FromNameField])))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && dr1[this._FreqField] != null)
                    {
                        int freq = (int)dr1[this._FreqField];
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
                else if (dr2[this._ToNamesField] != null && dr1[this._FromNameField] != null &&
                    ((List<string>)dr2[this._ToNamesField]).Contains(((string)dr1[this._FromNameField])))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && dr2[this._FreqField] != null)
                    {
                        int freq = (int)dr2[this._FreqField];
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
            }

            double? unDefined = null;
            return unDefined;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity1"></param>
        /// <param name="entity2"></param>
        /// <returns></returns>
        public double? CalculateLinkDistance(BaseEntity entity1, BaseEntity entity2)
        {
            if (!string.IsNullOrEmpty(this._FromIDField) && !string.IsNullOrEmpty(this._ToIDsField))
            {
                if (entity1.GetPropertyValue(this._ToIDsField) != null && entity2.GetPropertyValue(this._FromIDField) != null &&
                    ((List<int>)entity1.GetPropertyValue(this._ToIDsField)).Contains(((int)entity2.GetPropertyValue(this._FromIDField))))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && entity1.GetPropertyValue(this._FreqField) != null)
                    {
                        int freq = (int)entity1.GetPropertyValue(this._FreqField);
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
                else if (entity2.GetPropertyValue(this._ToIDsField) != null && entity1.GetPropertyValue(this._FromIDField) != null &&
                    ((List<int>)entity2.GetPropertyValue(this._ToIDsField)).Contains(((int)entity1.GetPropertyValue(this._FromIDField))))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && entity2.GetPropertyValue(this._FreqField) != null)
                    {
                        int freq = (int)entity2.GetPropertyValue(this._FreqField);
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
            }
            if (!string.IsNullOrEmpty(this._FromNameField) && !string.IsNullOrEmpty(this._ToNamesField))
            {
                if (entity1.GetPropertyValue(this._ToNamesField) != null && entity2.GetPropertyValue(this._FromNameField) != null &&
                    ((List<string>)entity1.GetPropertyValue(this._ToNamesField)).Contains(((string)entity2.GetPropertyValue(this._FromNameField))))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && entity1.GetPropertyValue(this._FreqField) != null)
                    {
                        int freq = (int)entity1.GetPropertyValue(this._FreqField);
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
                else if (entity2.GetPropertyValue(this._ToNamesField) != null && entity1.GetPropertyValue(this._FromNameField) != null &&
                    ((List<string>)entity2.GetPropertyValue(this._ToNamesField)).Contains(((string)entity1.GetPropertyValue(this._FromNameField))))
                {
                    if (!string.IsNullOrEmpty(this._FreqField) && entity2.GetPropertyValue(this._FreqField) != null)
                    {
                        int freq = (int)entity2.GetPropertyValue(this._FreqField);
                        if (freq > 0)
                            return 1.0 / Math.Sqrt(freq);
                        else
                            return 1.0;
                    }
                    else
                        return 1.0;
                }
            }

            double? unDefined = null;
            return unDefined;
        }

        #endregion
    }
}
